home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / gnu / groff_src.lha / Groff-1.07 / xditview / device.c < prev    next >
C/C++ Source or Header  |  1992-07-28  |  11KB  |  582 lines

  1. /* device.c */
  2.  
  3. #include <stdio.h>
  4. #include <ctype.h>
  5.  
  6. #include <X11/Xos.h>
  7. #include <X11/Intrinsic.h>
  8.  
  9. #include "device.h"
  10.  
  11. #ifndef FONTPATH
  12. #define FONTPATH "/usr/local/lib/groff/font:/usr/local/lib/font:/usr/lib/font"
  13. #endif
  14.  
  15. extern void exit();
  16. extern char *strtok(), *strchr();
  17. extern char *getenv();
  18.  
  19. /* Name of environment variable containing path to be used for
  20. searching for device and font description files. */
  21. #define FONTPATH_ENV_VAR  "GROFF_FONT_PATH"
  22.  
  23. #define WS " \t\r\n"
  24.  
  25. /* Minimum and maximum values a `signed int' can hold.  */
  26. #define INT_MIN (-INT_MAX-1)
  27. #define INT_MAX 2147483647
  28.  
  29. #define CHAR_TABLE_SIZE 307
  30.  
  31. struct _DeviceFont {
  32.     char *name;
  33.     int special;
  34.     DeviceFont *next;
  35.     Device *dev;
  36.     struct charinfo *char_table[CHAR_TABLE_SIZE];
  37.     struct charinfo *code_table[256];
  38. };
  39.  
  40. struct charinfo {
  41.     int width;
  42.     int code;
  43.     struct charinfo *next;
  44.     struct charinfo *code_next;
  45.     char name[1];
  46. };
  47.  
  48. static char *current_filename = 0;
  49. static int current_lineno = -1;
  50.  
  51. static void error();
  52. static FILE *open_device_file();
  53. static DeviceFont *load_font();
  54. static Device *new_device();
  55. static DeviceFont *new_font();
  56. static void delete_font();
  57. static unsigned hash_name();
  58. static struct charinfo *add_char();
  59. static int read_charset_section();
  60. static char *canonicalize_name();
  61.  
  62. static
  63. Device *new_device(name)
  64.     char *name;
  65. {
  66.     Device *dev;
  67.  
  68.     dev = XtNew(Device);
  69.     dev->sizescale = 1;
  70.     dev->res = 0;
  71.     dev->unitwidth = 0;
  72.     dev->fonts = 0;
  73.     dev->X11 = 0;
  74.     dev->paperlength = 0;
  75.     dev->paperwidth = 0;
  76.     dev->name = XtNewString(name);
  77.     return dev;
  78. }
  79.  
  80. void device_destroy(dev)
  81.     Device *dev;
  82. {
  83.     DeviceFont *f;
  84.     
  85.     if (!dev)
  86.     return;
  87.     f = dev->fonts;
  88.     while (f) {
  89.     DeviceFont *tem = f;
  90.     f = f->next;
  91.     delete_font(tem);
  92.     }
  93.     
  94.     XtFree(dev->name);
  95.     XtFree((char *)dev);
  96. }
  97.  
  98. Device *device_load(name)
  99.     char *name;
  100. {
  101.     Device *dev;
  102.     FILE *fp;
  103.     int err = 0;
  104.     char buf[256];
  105.  
  106.     fp = open_device_file(name, "DESC", ¤t_filename);
  107.     if (!fp)
  108.     return 0;
  109.     dev = new_device(name);
  110.     current_lineno = 0;
  111.     while (fgets(buf, sizeof(buf), fp)) {
  112.     char *p;
  113.     current_lineno++;
  114.     p = strtok(buf, WS);
  115.     if (p) {
  116.         int *np = 0;
  117.         char *q;
  118.  
  119.         if (strcmp(p, "charset") == 0)
  120.         break;
  121.         if (strcmp(p, "X11") == 0)
  122.         dev->X11 = 1;
  123.         else if (strcmp(p, "sizescale") == 0)
  124.         np = &dev->sizescale;
  125.          else if (strcmp(p, "res") == 0)
  126.         np = &dev->res;
  127.          else if (strcmp(p, "unitwidth") == 0)
  128.         np = &dev->unitwidth;
  129.          else if (strcmp(p, "paperwidth") == 0)
  130.         np = &dev->paperwidth;
  131.          else if (strcmp(p, "paperlength") == 0)
  132.         np = &dev->paperlength;
  133.         
  134.         if (np) {
  135.         q = strtok((char *)0, WS);
  136.         if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
  137.             error("bad argument");
  138.             err = 1;
  139.             break;
  140.         }
  141.         }    
  142.     }
  143.     }
  144.     fclose(fp);
  145.     current_lineno = -1;
  146.     if (!err) {
  147.     if (dev->res == 0) {
  148.         error("missing res line");
  149.         err = 1;
  150.     }
  151.     else if (dev->unitwidth == 0) {
  152.         error("missing unitwidth line");
  153.         err = 1;
  154.     }
  155.     }
  156.     if (dev->paperlength == 0)
  157.     dev->paperlength = dev->res*11;
  158.     if (dev->paperwidth == 0)
  159.     dev->paperwidth = dev->res*8 + dev->res/2;
  160.     if (err) {
  161.     device_destroy(dev);
  162.     dev = 0;
  163.     }
  164.     XtFree(current_filename);
  165.     current_filename = 0;
  166.     return dev;
  167. }
  168.  
  169.  
  170. DeviceFont *device_find_font(dev, name)
  171.     Device *dev;
  172.     char *name;
  173. {
  174.     DeviceFont *f;
  175.  
  176.     if (!dev)
  177.     return 0;
  178.     for (f = dev->fonts; f; f = f->next)
  179.     if (strcmp(f->name, name) == 0)
  180.         return f;
  181.     return load_font(dev, name);
  182. }
  183.  
  184. static
  185. DeviceFont *load_font(dev, name)
  186.     Device *dev;
  187.     char *name;
  188. {
  189.     FILE *fp;
  190.     char buf[256];
  191.     DeviceFont *f;
  192.     int special = 0;
  193.  
  194.     fp = open_device_file(dev->name, name, ¤t_filename);
  195.     if (!fp)
  196.     return 0;
  197.     current_lineno = 0;
  198.     for (;;) {
  199.     char *p;
  200.  
  201.     if (!fgets(buf, sizeof(buf), fp)) {
  202.         error("no charset line");
  203.         return 0;
  204.     }
  205.     current_lineno++;
  206.     p = strtok(buf, WS);
  207.     /* charset must be on a line by itself */
  208.     if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
  209.         break;
  210.     if (p && strcmp(p, "special") == 0)
  211.         special = 1;
  212.     }
  213.     f = new_font(name, dev);
  214.     f->special = special;
  215.     if (!read_charset_section(f, fp)) {
  216.     delete_font(f);
  217.     f = 0;
  218.     }
  219.     else {
  220.     f->next = dev->fonts;
  221.     dev->fonts = f;
  222.     }
  223.     fclose(fp);
  224.     XtFree(current_filename);
  225.     current_filename = 0;
  226.     return f;
  227. }
  228.  
  229. static
  230. DeviceFont *new_font(name, dev)
  231.     char *name;
  232.     Device *dev;
  233. {
  234.     int i;
  235.     DeviceFont *f;
  236.  
  237.     f = XtNew(DeviceFont);
  238.     f->name = XtNewString(name);
  239.     f->dev = dev;
  240.     f->special = 0;
  241.     f->next = 0;
  242.     for (i = 0; i < CHAR_TABLE_SIZE; i++)
  243.     f->char_table[i] = 0;
  244.     for (i = 0; i < 256; i++)
  245.     f->code_table[i] = 0;
  246.     return f;
  247. }
  248.  
  249. static
  250. void delete_font(f)
  251.     DeviceFont *f;
  252. {
  253.     int i;
  254.  
  255.     if (!f)
  256.     return;
  257.     XtFree(f->name);
  258.     for (i = 0; i < CHAR_TABLE_SIZE; i++) {
  259.     struct charinfo *ptr = f->char_table[i];
  260.     while (ptr) {
  261.         struct charinfo *tem = ptr;
  262.         ptr = ptr->next;
  263.         XtFree((char *)tem);
  264.     }
  265.     }
  266.     XtFree((char *)f);
  267. }
  268.  
  269.  
  270. static
  271. unsigned hash_name(name)
  272.     char *name;
  273. {
  274.     unsigned n = 0;
  275.     /* XXX do better than this */
  276.     while (*name)
  277.     n = (n << 1) ^ *name++;
  278.  
  279.     return n;
  280. }
  281.  
  282. static
  283. int scale_round(n, x, y)
  284.     int n, x, y;
  285. {
  286.   int y2;
  287.  
  288.   if (x == 0)
  289.     return 0;
  290.   y2 = y/2;
  291.   if (n >= 0) {
  292.     if (n <= (INT_MAX - y2)/x)
  293.       return (n*x + y2)/y;
  294.   }
  295.   else if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
  296.       return (n*x - y2)/y;
  297.   return (int)(n*(double)x/(double)y + .5);
  298. }
  299.  
  300. static
  301. char *canonicalize_name(s)
  302.     char *s;
  303. {
  304.     static char ch[2];
  305.     if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
  306.     char *p;
  307.     int n;
  308.  
  309.     for (p = s + 4; *p; p++)
  310.         if (!isascii(*p) || !isdigit(*p))
  311.         return s;
  312.     n = atoi(s + 4);
  313.     if (n >= 0 && n <= 0xff) {
  314.         ch[0] = (char)n;
  315.         return ch;
  316.     }
  317.     }
  318.     return s;
  319. }
  320.  
  321. /* Return 1 if the character is present in the font; widthp gets the
  322. width if non-null. */
  323.  
  324. int device_char_width(f, ps, name, widthp)
  325.     DeviceFont *f;
  326.     int ps;
  327.     char *name;
  328.     int *widthp;
  329. {
  330.     struct charinfo *p;
  331.  
  332.     name = canonicalize_name(name);
  333.     for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
  334.     if (!p)
  335.         return 0;
  336.     if (strcmp(p->name, name) == 0)
  337.         break;
  338.     }
  339.     *widthp = scale_round(p->width, ps, f->dev->unitwidth);
  340.     return 1;
  341. }
  342.  
  343. int device_code_width(f, ps, code, widthp)
  344.     DeviceFont *f;
  345.     int ps;
  346.     int code;
  347.     int *widthp;
  348. {
  349.     struct charinfo *p;
  350.  
  351.     for (p = f->code_table[code & 0xff];; p = p->code_next) {
  352.     if (!p)
  353.         return 0;
  354.     if (p->code == code)
  355.         break;
  356.     }
  357.     *widthp = scale_round(p->width, ps, f->dev->unitwidth);
  358.     return 1;
  359. }
  360.  
  361. char *device_name_for_code(f, code)
  362.     DeviceFont *f;
  363.     int code;
  364. {
  365.     static struct charinfo *state = 0;
  366.     if (f)
  367.     state = f->code_table[code & 0xff];
  368.     for (; state; state = state->code_next)
  369.     if (state->code == code && state->name[0] != '\0') {
  370.         char *name = state->name;
  371.         state = state->code_next;
  372.         return name;
  373.     }
  374.     return 0;
  375. }
  376.  
  377. int device_font_special(f)
  378.     DeviceFont *f;
  379. {
  380.     return f->special;
  381. }
  382.     
  383. static
  384. struct charinfo *add_char(f, name, width, code)
  385.     DeviceFont *f;
  386.     char *name;
  387.     int width, code;
  388. {
  389.     struct charinfo **pp;
  390.     struct charinfo *ci;
  391.     
  392.     name = canonicalize_name(name);
  393.     if (strcmp(name, "---") == 0)
  394.     name = "";
  395.  
  396.     ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
  397.                      + strlen(name) + 1);
  398.     
  399.     strcpy(ci->name, name);
  400.     ci->width = width;
  401.     ci->code = code;
  402.     
  403.     if (*name != '\0') {
  404.     pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
  405.     ci->next = *pp;
  406.     *pp = ci;
  407.     }
  408.     pp = &f->code_table[code & 0xff];
  409.     ci->code_next = *pp;
  410.     *pp = ci;
  411.     return ci;
  412. }
  413.  
  414. /* Return non-zero for success. */
  415.  
  416. static
  417. int read_charset_section(f, fp)
  418.     DeviceFont *f;
  419.     FILE *fp;
  420. {
  421.     struct charinfo *last_charinfo = 0;
  422.     char buf[256];
  423.  
  424.     while (fgets(buf, sizeof(buf), fp)) {
  425.     char *name;
  426.     int width;
  427.     int code;
  428.     char *p;
  429.  
  430.     current_lineno++;
  431.     name = strtok(buf, WS);
  432.     if (!name)
  433.         continue;        /* ignore blank lines */
  434.     p = strtok((char *)0, WS);
  435.     if (!p)            /* end of charset section */
  436.         break;
  437.     if (strcmp(p, "\"") == 0) {
  438.         if (!last_charinfo) {
  439.         error("first line of charset section cannot use `\"'");
  440.         return 0;
  441.         }
  442.         else
  443.         (void)add_char(f, name,
  444.                    last_charinfo->width, last_charinfo->code);
  445.     }
  446.     else {
  447.         char *q;
  448.         if (sscanf(p, "%d", &width) != 1) {
  449.         error("bad width field");
  450.         return 0;
  451.         }
  452.         p = strtok((char *)0, WS);
  453.         if (!p) {
  454.         error("missing type field");
  455.         return 0;
  456.         }
  457.         p = strtok((char *)0, WS);
  458.         if (!p) {
  459.         error("missing code field");
  460.         return 0;
  461.         }
  462.         code = (int)strtol(p, &q, 0);
  463.         if (q == p) {
  464.         error("bad code field");
  465.         return 0;
  466.         }
  467.         last_charinfo = add_char(f, name, width, code);
  468.     }
  469.     }
  470.     return 1;
  471. }
  472.  
  473. static
  474. FILE *find_file(file, path, result)
  475.     char *file, *path, **result;
  476. {
  477.   char *buf = NULL;
  478.   int bufsiz = 0;
  479.   int flen;
  480.   FILE *fp;
  481.   
  482.   *result = NULL;
  483.   
  484.   if (file == NULL)
  485.     return NULL;
  486.   if (*file == '\0')
  487.     return NULL;
  488.   
  489.   if (*file == '/') {
  490.     fp = fopen(file, "r");
  491.     if (fp)
  492.       *result = XtNewString(file);
  493.     return fp;
  494.   }
  495.   
  496.   flen = strlen(file);
  497.   
  498.   if (!path)
  499.     return NULL;
  500.   
  501.   while (*path) {
  502.     int len;
  503.     char *start, *end;
  504.     
  505.     start = path;
  506.     end = strchr(path, ':');
  507.     if (end)
  508.       path = end + 1;
  509.     else
  510.       path = end = strchr(path, '\0');
  511.     if (start >= end)
  512.       continue;
  513.     if (end[-1] == '/')
  514.       --end;
  515.     len = (end - start) + 1 + flen + 1;
  516.     if (len > bufsiz) {
  517.       if (buf)
  518.     buf = XtRealloc(buf, len);
  519.       else
  520.     buf = XtMalloc(len);
  521.       bufsiz = len;
  522.     }
  523.     memcpy(buf, start, end - start);
  524.     buf[end - start] = '/';
  525.     strcpy(buf + (end - start) + 1, file);
  526.     fp = fopen(buf, "r");
  527.     if (fp) {
  528.       *result = buf;
  529.       return fp;
  530.     }
  531.   }
  532.   XtFree(buf);
  533.   return NULL;
  534. }
  535.  
  536. static
  537. FILE *open_device_file(device_name, file_name, result)
  538.      char *device_name, *file_name, **result;
  539. {
  540.   char *buf, *path;
  541.   FILE *fp;
  542.  
  543.   buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
  544.   sprintf(buf, "dev%s/%s", device_name, file_name);
  545.   path = getenv(FONTPATH_ENV_VAR);
  546.   if (!path)
  547.     path = FONTPATH;
  548.   fp = find_file(buf, path, result);
  549.   if (!fp) {
  550.       fprintf(stderr, "can't find device file `%s'\n", file_name);
  551.       fflush(stderr);
  552.   }
  553.   XtFree(buf);
  554.   return fp;
  555. }
  556.  
  557. static
  558. void error(s)
  559.     char *s;
  560. {
  561.     if (current_filename) {
  562.     fprintf(stderr, "%s:", current_filename);
  563.     if (current_lineno > 0)
  564.         fprintf(stderr, "%d:", current_lineno);
  565.     putc(' ', stderr);
  566.     }
  567.     fputs(s, stderr);
  568.     putc('\n', stderr);
  569.     fflush(stderr);
  570. }
  571.  
  572. /*
  573. Local Variables:
  574. c-indent-level: 4
  575. c-continued-statement-offset: 4
  576. c-brace-offset: -4
  577. c-argdecl-indent: 4
  578. c-label-offset: -4
  579. c-tab-always-indent: nil
  580. End:
  581. */
  582.